#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#define NUM 1024
#define CMDSIZE 64
//redir
#define APPENDREDIR 2
#define InputRedir 3
#define OutputRedir 1
#define NoneRedir 0

int redir = 0;
char *filename = NULL;
char enval[1024];
char cwd[1024];
int lastcode = 0;
const char* getUname()
{
    return getenv("USER");
}
const char* getHname()
{
    return getenv("HOSTNAME");
}
const char* getCwd()
{
    return getenv("PWD");
}
int getUsrCmd(char* usrCmd,int num)
{

   printf("[%s@%s %s]:",getUname(),getHname(),getCwd());    
   char* rstr=  fgets(usrCmd,NUM,stdin);
   if(rstr==NULL)
   {
       return 1;
   }
   usrCmd[strlen(usrCmd)-1] = 0;//由于至少会读取\n，就不存在数组越界的情况

   return strlen(usrCmd);
}
void commandSplit(char* in,char* argv[])
{ 
    int argc = 0;
    for(char* tmp=strtok(in," ");tmp;tmp = strtok(NULL," "))
    {
        argv[argc++] = tmp;
    }
    argv[argc] = NULL;
#ifdef Debug
    for(int i = 0;i<argc;i++)
    {
        printf("%d:%s\n",i,argv[i]);
    }
#endif
}
void cd(const char *path)
{
    chdir(path);
    char tmp[1024];
    getcwd(tmp, sizeof(tmp));
    sprintf(cwd, "PWD=%s", tmp); // bug
    putenv(cwd);
}
int DoCmdIsIn(char *argv[])
{
    if(strcmp(argv[0], "cd") == 0)
    {
        char *path = NULL;
        if(argv[1] == NULL) path = ".";
        else path = argv[1];
        cd(path);
        return 1;
    }
    else if(strcmp(argv[0], "export") == 0)
    {
        if(argv[1] == NULL) return 1;
        strcpy(enval, argv[1]);
        putenv(enval); // ???
        return 1;
    }
    else if(strcmp(argv[0], "echo") == 0)
    {
        char *val = argv[1]+1; // $PATH $?
        if(strcmp(val, "?") == 0)
        {
            printf("%d\n", lastcode);
            lastcode = 0;
        }
        else{
            printf("%s\n", getenv(val));
        }
        return 1;
    }
    else if(0){}

    return 0;
}

int execute(char* argv[])
{

        pid_t pid = fork();
        if(pid<0)
        {
            return 1;
        }
        else if(pid==0)
        {
            int fd= 0;
            if(redir == InputRedir)
            {
                fd = open(filename, O_RDONLY);
                dup2(fd,0);
            }
            else if(redir == OutputRedir)
            {
                fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666);
                dup2(fd,1);
            }
            else if(redir == APPENDREDIR)
            {
                fd = open(filename,O_WRONLY | O_CREAT | O_APPEND,0666);
                dup2(fd,1);
            }
            else{
                //nothin done
            }
            execvp(argv[0],argv);
            exit(1);
        }
        else{

            int status = 0;
            pid_t rid = waitpid(pid,&status,0);
            if(rid>0)
            {
                lastcode = WEXITSTATUS(status);
            }
        }
        return 0;
}

void SkipSpace(char* str)
{
    while(isspace(*str))
    {
       str++;
    }
}

void checkRedir(char* usercommand,int len)
{
    char *end = usercommand +len-1;
    char* start = usercommand;
    while(end>start)
    {
        if(*end == '>')
        {
            if(*(end-1) == '>')
            {
                *(end-1) = '\0';
                filename = end+1;
                SkipSpace(filename);
                redir = APPENDREDIR;
                break;
            }
            else{
                *end = '\0';
                filename = end+1;
                SkipSpace(filename);
                redir = OutputRedir;
                break;
            }
        }
        else if(*end == '<')
        {
            redir = InputRedir;
            *end ='\0';
            filename = end+1;
            SkipSpace(filename);
            break;
        }
        else{
        end--;
        }
    }
    return;
}
int main()
{
    while(1)
    {    
        filename = NULL;
        redir = NoneRedir;
        char usrCmd[NUM] = {0};
        //1.能成功打印就算成功
        int n =  getUsrCmd(usrCmd,NUM);
        if(n<=0)
        {
            continue;
        }
        checkRedir(usrCmd,n); 
        //2.分割字符串
        char * argv[100];
        commandSplit(usrCmd,argv);
        if(!DoCmdIsIn(argv))
        execute(argv);
        //3.创建子进程执行命令
    }
    return 0;
}
